﻿namespace BlogsAPI.Search
{
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Text.RegularExpressions;
    using Abstract;
    using System.Web;
    using System.Diagnostics;
    using System;

    /// <summary>
    /// Класс для работы с поиском поисковой системой plazoo
    /// </summary>
    /// <remarks>http://search.otvet.mail.ru/?q=%F1%E2%FF%E7%ED%EE%E9&zdts=-259200&big=2&s=zdts</remarks>
    public class OtvetMail : BasicSearch
    {
        private readonly Regex rParser = new Regex(@"<div\s+class\W+det[^<]+<a\s+href\W+(http[^'""]+)[^>]+>(.+?)(?:</a>)[^>]+>([^<]+).*?(?:<div\s+class\W+black[^>]+)>(.*?)</div>"
        ,Regexoptions);

        /// <summary>
        /// Конструктор
        /// </summary>
        public OtvetMail()
        {
            separator_and = "|";
            separator_not = "!";
        }

        /// <summary>
        /// Получение сложно-параметрического запроса
        /// Типа, Любое из First и Любое из Second, но не Except
        /// </summary>
        /// <param name="First">Слова для поиска</param>
        /// <param name="Second">Слова для поиска 2</param>
        /// <param name="Except">Исключающие слова</param>
        /// <returns></returns>
        public override String FormQueryString(string[] First, string[] Second, string[] Except)
        {
            //игнорируем вторую строчку, ищем только по первой., а потом выкидываем все, что есть в Except
            return (First == null ? "" : String.Join(separator_and, First)) +
                separator_not + (Second == null ? "" : String.Join(separator_and, Second)) +
                separator_not + (Except == null ? "" : String.Join(separator_and, Except));
        }

        /// <summary>
        /// Формируем ссылку для поиска 
        /// </summary>
        private static String FormSearch(String text, DateTime? fromDate)
        {
            return String.Format("http://search.otvet.mail.ru/?q={0}&big=2&s=zdts{1}",
                HttpUtility.UrlEncode(text).Replace("&", "%26"), 
                fromDate == null ? "" : "&zdts=-" + ((TimeSpan)(DateTime.Now - fromDate)).TotalSeconds);
        }

        /// <summary>
        /// Формирование разобранного поста из того что дает яндекс.
        /// </summary>
        /// <returns></returns>
        private BlogPost ParseBlogPost(Match m)
        {
            return new BlogPost
            {
                Link = new Uri(m.Groups[1].Value),
                Body = m.Groups[4].Value.Trim(),
                Subject = m.Groups[2].Value.Trim(),
                Existance = true,
                Published = DateTime.Now,
                //в [3] у нас список категорий
                Attributes = new PostAttributeCollection
                { new PostAttribute(PostParams.Tags, m.Groups[3].Value.Trim()) }
            };
        }


        /// <summary>
        /// </summary>
        /// <param name="text">текст для поиска</param>
        /// <param name="fromDate">дата начиная с которой искать объекты, может быть нулом, тогде по максимуму!</param>
        /// <returns>массив постов удовлетворяющих поиску</returns>
        public override BlogPost[] SearchFor(String text, DateTime? fromDate)
        {
            BlogPost[] oRes = new BlogPost[0];
            try
            {
                //1 - преобразуем запросный текст из строчки в массив!
                string[] First = text.Split(new []{separator_not},StringSplitOptions.None);//чтобы всегда было 3 элемента
                string[] Second = First.Length>1?First[1].Split(new[] { separator_and }, StringSplitOptions.RemoveEmptyEntries):null;
                string[] Except = First.Length>2?First[2].Split(new[] { separator_and }, StringSplitOptions.RemoveEmptyEntries):null;
                First = First[0].Split(new[] { separator_and }, StringSplitOptions.RemoveEmptyEntries);

                foreach (string onerequest in First)
                {
                    HttpWebRequest myHttpWebRequest = MakeRequest(FormSearch(onerequest, fromDate));
                    myHttpWebRequest.AllowAutoRedirect = false;
                    myHttpWebRequest.Method = "GET";
                    HttpWebResponse myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
                    string reply = (new StreamReader(myHttpWebResponse.GetResponseStream(),
                        Encoding.GetEncoding(myHttpWebResponse.CharacterSet) )).ReadToEnd();
                    myHttpWebResponse.Close();

                    ParseResult(reply, ref oRes, Second, Except);
                }
            }
            catch (Exception e1)
            {
                Debug.WriteLine("SearchFor failed cause " + e1.Message);
            }
            return oRes;
        }

        /// <summary>
        /// Разборка полученного результата
        /// </summary>
        /// <param name="sPage">страница ответа</param>
        /// <param name="oRes">массив найденного</param>
        private void ParseResult(string sPage, ref BlogPost[] oRes,string[] Second,string[] Except)
        {
            Regex rSecond = new Regex(String.Format(@"\b(?:{0})\b", Second == null ? "" : String.Join("|", Second)),
                            Regexoptions);
            
            Regex rExc = new Regex(String.Format(@"\b(?:{0})\b", Except==null?"":String.Join("|", Except)),
                            Regexoptions);
            MatchCollection mc = rParser.Matches(sPage);
            if(mc.Count>0)
            {
                foreach (Match m in mc)
                {
                    BlogPost bp = ParseBlogPost(m);
                    //убедимся что в найденном есть фразы из второй строчки
                    if(Second!=null && Second.Length>0)
                    {
                        if (!rSecond.Match(bp.Subject + " " + bp.Body).Success)
                        {
                            continue;//нет нужных слов
                        } 
                    }

                    //убедимся что в найденном нет слов исключений
                    if (Except != null && Except.Length>0)
                    {
                        if(rExc.Match(bp.Subject+" "+bp.Body).Success)
                        {
                            continue;//есть исключения
                        }
                    }
                    Array.Resize(ref oRes, oRes.Length + 1);
                    oRes[oRes.Length - 1] = bp;
                }
            }
        }
    }
}
